#
# Copyright (C) [2024] Xingyun Integrated Circuit, Inc.
#
#   GreenCode was a private technology asset of Xingyun Integrated Circuit， Inc （Confidential）
#   Author :  Shawn.Tan
#   Date : 2025.10.28
#
#   History : Initial Version 2025.10.28
#
#
from base.Sequence import Sequence
import inspect
import sys
import os


#  AddressTableGPGPU
# Provide available address for exceptions handlers.
class AddressTableGPGPU(Sequence):
    def __init__(self, gen_thread):
        super().__init__(gen_thread)
        self.table_index = None
        self._mAppRegSize = 64

    def generate(self, **kwargs):
        self.table_index = kwargs.get("table_index", None)
        if self.table_index is None:
            self.table_index = self.getRandomGPR(exclude="0,1,2")
        self.reserveRegisterByIndex(64, self.table_index, "GPR", "ReadWrite")
        self._mAppRegSize = self.getGlobalState("AppRegisterWidth")

        return self.table_index

    def tableIndex(self):
        return self.table_index

    def getAddress(self, reg_index, scratch_index):
        # Load the value pointed to by the reg table_index into reg
        # reg_index and then increment the value in the reg table_index by 8
        self.genLoadRegFromDataBlock(reg_index, self.table_index, True)

        # get scratch GPR and load it with the number 1
        self.genInstruction("ADDI##CALM", {"rd": scratch_index, "rs1": 0, "simm12": 1})

        # Compare the value that had been loaded into reg reg_index to one.
        # One means the table entry after this one is actually the address
        # of another table.
        pc = self.getPEstate("PC")
        self.genInstruction(
            "BNE##CALM",
            {
                "rs1": scratch_index,
                "rs2": reg_index,
                "simm12": 8,
                "NoBnt": 1,
                "NoRestriction": 1,
            },
        )
        self.setPEstate("PC", pc + 4)

        # Load the value pointed to by the reg table_index into reg
        # table_index.
        self.genLoadRegFromDataBlock(self.table_index, self.table_index)

        # Load the value pointed to by the reg table_index into reg
        # reg_index and then increment the value in the reg table_index by 8
        self.genLoadRegFromDataBlock(reg_index, self.table_index, True)

    def genLoadRegFromDataBlock(self, aDestReg, aAddrReg, aIncrementAddr=False):
        if self._mAppRegSize == 32:
            instr = "LW##CALM"
            data_size = 4
        else:
            instr = "LD##CALM"
            data_size = 8

        self.genInstruction(
            instr,
            {
                "rd": aDestReg,
                "rs1": aAddrReg,
                "simm12": 0,
                "NoRestriction": 1,
            },
        )
        if aIncrementAddr:
            self.genInstruction(
                "ADDI##CALM",
                {"rd": aAddrReg, "rs1": aAddrReg, "simm12": data_size},
            )


#  AddressTableManagerGPGPU class
class AddressTableManagerGPGPU(Sequence):
    def __init__(self, gen_thread):
        super().__init__(gen_thread)
        self.table_index = None  # address table index
        self.address_table = None  # address table

    def generate(self):
        self.address_table = AddressTableGPGPU(self.genThread)
        self.table_index = self.address_table.generate(table_index=self.table_index)
        fast_mode = self.genThread.fastMode
        addr_table_info_set = {
            "table_index": self.table_index,
            "fast_mode": fast_mode,
        }
        self.genSequence("InitializeAddrTables", addr_table_info_set)

    # only copy table index.
    def createShallowCopy(self, gen_thread):
        address_table_manager_copy = AddressTableManagerGPGPU(gen_thread)
        address_table_manager_copy.table_index = self.table_index
        return address_table_manager_copy

    def addressTable(self):
        return self.address_table
